import Want from '@ohos.application.Want';
import fileIo from '@ohos.fileio';
// @ts-ignore
import fs from '@ohos.file.fs';
// @ts-ignore
import fileShare from "@ohos.fileShare";
// @ts-ignore
import fileUri from "@ohos.file.fileuri";
import wantConstant from '@ohos.ability.wantConstant';
import Utils from './Utils';
// @ts-ignore
import bundleManager from '@ohos.bundle.bundleManager';
import deviceManager from '@ohos.distributedHardware.deviceManager';

export default class MyFileIo {
    private utils = new Utils();
    private common_fd: number = -1;

    constructor() {

    }

    ForTest() {
        this.utils.myLog("ForTest start:");
    }

    //跳转应用并授权
    grantFileUriPermission(filePath: string, flags: number) {
        let abilityContext = globalThis.abilityContext;
        this.utils.myLog("function start:");
        let mode;
        switch (flags) {
            case 0:
                mode = wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION;
                break;
            case 1:
                mode = wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION;
                break;
            case 2:
                mode = wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION;
                break;
        }

        try {
            //分享文件处理逻辑
            let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
            if (file == undefined) {
                this.utils.myErrLog("open failed failed ");
                return;
            }
            // @ts-ignore
            deviceManager.createDeviceManager("com.demo.a", (err, deviceManager) => {
                let deviceList = deviceManager.getTrustedDeviceListSync();
                let networkId = '';
                if ( deviceList.length > 0){
                    networkId = deviceList[0].networkId;
                    this.utils.myLog("networkId = " + networkId);
                } else {
                    this.utils.myLog("get trust device list is empty");
                }
                //组装跳转数据
                let uri: string = fileUri.getUriFromPath(filePath);
                this.utils.myLog("uri = " + uri + ", deviceId = " + networkId);
                let uris: string[] = [uri];

                let want: Want = {
                    action: "ohos.want.action.sendData",
                    parameters: {
                        "ability.params.stream": uris
                    },
                    flags: mode,
                    bundleName: "com.demo.b",
                    abilityName: "MainAbility",
                    type: "text/plain",
                    deviceId: networkId,
                    uri: uri,
                }
                //执行跳转
                abilityContext.startAbility(want)
                    .then(() => {
                        // 执行正常业务
                        this.utils.myLog('startAbility succeed');
                    })
                    .catch((error) => {
                        // 处理业务逻辑错误
                        this.utils.myErrLog('startAbility failed, error.code = ' + JSON.stringify(error.code) +
                        ' error.message = ' + JSON.stringify(error.message));
                    });
            });
        } catch (paramError) {
            this.utils.myErrLog("error code = " + paramError.code + ", error message = " + paramError.message);
        }
    }

    grantUriPermissionCallbackR(uri: string, bundleName: string) {
        let myUtils = this.utils;
        myUtils.myLog("grantUriPermissionCallbackR: bundleName = " + bundleName);
        myUtils.myLog("grantUriPermissionCallbackR: uri = " + uri);
        try {
            fileShare.grantUriPermission(uri, bundleName, "r", (err) => {
                if (err) {
                    myUtils.myErrLog("grantUriPermissionCallbackR: grantUriPermission failed with error: " + err);
                    return;
                }
                myUtils.myLog("grantUriPermissionCallbackR: grantUriPermission success!");
            });
        } catch (error) {
            myUtils.myErrLog("grantUriPermissionCallbackR: grantUriPermission failed with error:" + error);
        }
    }

    grantUriPermissionCallbackW(uri: string, bundleName: string) {
        let myUtils = this.utils;
        myUtils.myLog("grantUriPermissionCallbackW: bundleName = " + bundleName);
        myUtils.myLog("grantUriPermissionCallbackW: uri = " + uri);
        try {
            fileShare.grantUriPermission(uri, bundleName, "w", (err) => {
                if (err) {
                    myUtils.myErrLog("grantUriPermissionCallbackW: grantUriPermission failed with error: " + err);
                    return;
                }
                myUtils.myLog("grantUriPermissionCallbackW: grantUriPermission success!");
            });
        } catch (error) {
            myUtils.myErrLog("grantUriPermissionCallbackW: grantUriPermission failed with error: " + error);
        }
    }

    grantUriPermissionPromiseRW(uri: string, bundleName: string) {
        let myUtils = this.utils;
        myUtils.myLog("grantUriPermissionPromiseRW: uri = " + uri);
        myUtils.myLog("grantUriPermissionPromiseRW: bundleName = " + bundleName);
        try {
            fileShare.grantUriPermission(uri, bundleName, wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION).then(function () {
                myUtils.myLog("grantUriPermissionPromiseRW: grantUriPermission success!");
            }).catch(function (error) {
                myUtils.myErrLog("grantUriPermissionPromiseRW: grantUriPermission async failed with error:" + error);
            });
        } catch (error) {
            myUtils.myErrLog("grantUriPermissionPromiseRW: grantUriPermission failed with error:" + error);
        }
    }

    // @ts-ignore
    async getUriFromPath(path: string, context: Context) {
        let uri = null;
        uri = fileUri.getUriFromPath(path);
        this.utils.myLog("uri：" + uri);
        this.utils.myLog("getUriFromPath end");
        return uri;
    }

    // @ts-ignore
    async getApplicationInfoCallback(context: Context) {
        let bundleName = context.applicationInfo.name;
        // @ts-ignore
        let appFlags = bundleManager.ApplicationFlag.GET_APPLICATION_INFO_DEFAULT;
        let userId = 100;
        try {
            // @ts-ignore
            let data = await bundleManager.getApplicationInfo(bundleName, appFlags, userId)
            this.utils.myLog("getApplicationInfo successfully: data = " + JSON.stringify(data));
            this.utils.myLog("data.accessTokenId: " + data.accessTokenId);
            return data;
        } catch (err) {
            this.utils.myErrLog('getApplicationInfo failed err = ' + err.message);
        }
    }

    /**********************************************fileIo相关操作*******************************************************/

    getMode(openFlag: number): number {
        let mode;
        switch (openFlag) {
            case 0:
                mode = fs.OpenMode.CREATE | fs.OpenMode.READ_ONLY; // c | r
                break;
            case 1:
                mode = fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY; // c | w
                break;
            case 2:
                mode = fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE; // c | rw
                break;
            case 3:
                mode = fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY | fs.OpenMode.APPEND; // c | wa
                break;
            case 4:
                mode = fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC; // c | wt
                break;
            case 5:
                mode = fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND; // c | rwa
                break;
            case 6:
                mode = fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC; // c | rwt
                break;
        }
        return mode;
    }

    openReadFileFromFd(path: string, openFlag: number, execFlag: number, isWrite: boolean = true, isClose: boolean = true) {
        let mode = this.getMode(openFlag);
        this.utils.myLog("open path = " + path);
        this.utils.myLog("open mode = " + mode);
        switch (execFlag) {
            case 0:
                this.utils.myLog("exec sync")
                this.openReadWriteSync(path, mode, isWrite, isClose);
                break;
            case 1:
                this.utils.myLog("exec callback")
                this.openReadWriteCallback(path, mode, isWrite, isClose);
                break;
            case 2:
                this.utils.myLog("exec promise")
                this.openReadWritePromise(path, mode, isWrite, isClose);
                break;
        }
    }

    /*****************************Sync********************************/
    //sync-open-read-write
    openReadWriteSync(uri: string, mode: number, isWrite: boolean, isClose: boolean) {
        let myUtils = this.utils;
        let file;
        if (isClose || this.common_fd == -1) {
            try {
                file = fs.openSync(uri, mode);
                myUtils.myLog("openReadSync: get fd success. fd = " + file.fd);
                this.common_fd = file.fd;
            } catch (err) {
                myUtils.myErrLog("openReadSync: open file failed. error = " + err);
            }
            if (file == undefined) {
                myUtils.myErrLog("openReadSync: open file failed. file = undefined.");
                return;
            }
        }
        this.myReadSync(this.common_fd, !isClose, isWrite);
        this.myReadSync(this.common_fd, isClose, !isWrite);
    }

    //sync-read-write
    myReadSync(fd: number, isClose: boolean, isWrite: boolean) {
        try {
            let buffer = new ArrayBuffer(4096);
            let readOut = fs.readSync(fd, buffer, {
                offset: 0
            });
            this.utils.myLog("myReadSync: read result: " + String.fromCharCode.apply(null, new Uint8Array(buffer.slice(0, readOut))));
        } catch (err) {
            this.utils.myErrLog("myReadSync: read error: " + err);
        }
        if (isWrite) {
            this.myWriteSync(fd, "~myWriteSync~11111111111111111~com.demo.a~^", isClose);
        } else {
            if (isClose) {
                this.closeSync(fd);
                this.common_fd = -1;
            } else {
                this.common_fd = fd;
            }
        }
    }

    //sync-write-close
    myWriteSync(fd: number, content: string, isClose: boolean) {
        try {
            let result = fs.writeSync(fd, content);
            this.utils.myLog("myWriteSync: write result = " + result);
        } catch (err) {
            this.utils.myErrLog("myWriteSync： write failed with error:" + err);
        }
        if (isClose) {
            this.closeSync(fd);
            this.common_fd = -1;
        } else {
            this.common_fd = fd;
        }
    }

    //sync-close
    closeSync(fd: number) {
        try {
            fileIo.closeSync(fd);
            this.utils.myLog("closeSync file finish.");
        } catch (err) {
            this.utils.myErrLog("closeSync file error = " + err);
        }
    }

    /*****************************callback********************************/
    //callback打开调读
    openReadWriteCallback(uri: string, mode: number, isWrite: boolean, isClose: boolean) {
        let context = this;
        let myUtils = context.utils;
        if (isClose || this.common_fd == -1) {
            fs.open(uri, mode, (err, file) => {
                if (file != undefined) {
                    myUtils.myLog("openReadWriteCallback: get fd success, fd = " + file.fd);
                    this.common_fd = file.fd;
                    context.myReadCallback(this.common_fd, isWrite, isClose);
                } else {
                    myUtils.myErrLog("openReadWriteCallback: open file failed with error:" + err);
                }
            });
        } else {
            context.myReadCallback(this.common_fd, isWrite, isClose);
        }
    }

    //callback读调关闭
    myReadCallback(fd: number, isWrite: boolean, isClose: boolean) {
        let buffer = new ArrayBuffer(4096);
        try {
            fs.read(fd, buffer, {
                offset: 0
            }, (err, readOut) => {
                if (err) {
                    this.utils.myErrLog("myReadCallback： read data to file failed read error:" + err);
                } else {
                    this.utils.myLog("myReadCallback: read result: " + String.fromCharCode.apply(null, new Uint8Array(buffer.slice(0, readOut))));
                }
                if (isWrite) {
                    this.myWriteCallback(this.common_fd, "~myWriteCallback~sssdasdcccc^", isClose);
                } else {
                    if (isClose) {
                        this.closeCallback(fd);
                        this.common_fd = -1;
                    } else {
                        this.common_fd = fd;
                    }
                }
            });
        } catch (err) {
            this.utils.myErrLog("myReadCallback： read error:" + err);
            if (isClose) {
                this.closeCallback(fd);
                this.common_fd = -1;
            } else {
                this.common_fd = fd;
            }
        }
    }

    //callback写调关闭
    myWriteCallback(fd: number, content: string, isClose: boolean) {
        let context = this;
        let myUtils = this.utils;
        try {
            fs.write(fd, content, function (err, bytesWritten) {
                if (bytesWritten) {
                    myUtils.myLog("myWriteCallback： write succeed and size is:" + bytesWritten);
                } else if (err) {
                    myUtils.myErrLog("myWriteCallback： write failed with error:" + err);
                }
                if (isClose) {
                    context.closeCallback(fd);
                    context.common_fd = -1;
                } else {
                    context.common_fd = fd;
                }
            });
        } catch (err) {
            myUtils.myErrLog("myWriteCallback： write failed with error:" + err);
            if (isClose) {
                context.closeCallback(fd);
                context.common_fd = -1;
            } else {
                context.common_fd = fd;
            }
        }
    }

    //callback关闭fd
    closeCallback(fd: number) {
        let myUtils = this.utils;
        try {
            fileIo.close(fd, (info) => {
                myUtils.myLog("closeCallback： close file succeed. info =" + info);
            });
        } catch (err) {
            myUtils.myErrLog("closeCallback: close file failed with error:" + err);
        }
    }

    /*****************************Promise********************************/
    //open-read
    openReadWritePromise(uri: string, mode: number, isWrite: boolean, isClose: boolean) {
        let context = this;
        let myUtils = context.utils;
        if (isClose || this.common_fd == -1) {
            fs.open(uri, mode).then(function (file) {
                myUtils.myLog("openPromise: get fd success. fd = " + file.fd);
                context.common_fd = file.fd;
                context.myReadPromise(context.common_fd, isWrite, isClose);
            }).catch(function (err) {
                myUtils.myErrLog("openPromise: open file failed. error = " + err);
            });
        } else {
            context.myReadPromise(context.common_fd, isWrite, isClose);
        }
    }
    //read-write
    myReadPromise(fd: number, isWrite: boolean, isClose: boolean) {
        let context = this;
        let myUtils = this.utils;
        let buffer = new ArrayBuffer(4096);
        fs.read(fd, buffer, {
            offset: 0
        }).then(function (readOut) {
            myUtils.myLog("myReadPromise: read result: " + String.fromCharCode.apply(null, new Uint8Array(buffer.slice(0, readOut))));
            if (isWrite) {
                context.myWritePromise(fd, "~myWritePromise~33333333333333333~~~~~^", isClose);
            } else {
                if (isClose) {
                    context.closePromise(fd);
                    this.common_read_fd = -1;
                } else {
                    this.common_read_fd = fd;
                }
            }
        }).catch(function (err) {
            myUtils.myErrLog("myReadPromise: promise running error" + err);
            if (isClose) {
                context.closePromise(fd);
                this.common_read_fd = -1;
            } else {
                this.common_read_fd = fd;
            }
        });
    }
    //write-close
    myWritePromise(fd: number, content: string, isClose: boolean) {
        let context = this;
        let myUtils = this.utils;
        fs.write(fd, content).then(function (number) {
            myUtils.myLog("myWritePromise： write succeed and size is:" + number);
            if (isClose) {
                context.closePromise(fd);
                context.common_fd = -1;
            } else {
                context.common_fd = fd;
            }
        }).catch(function (err) {
            myUtils.myErrLog("myWritePromise： write failed with error:" + err);
            if (isClose) {
                context.closePromise(fd);
                context.common_fd = -1;
            } else {
                context.common_fd = fd;
            }
        });
    }
    //close
    closePromise(fd: number) {
        let myUtils = this.utils;
        fileIo.close(fd).then(function () {
            myUtils.myLog("closePromise： close file succeed");
        }).catch(function (err) {
            myUtils.myErrLog("closePromise： close file failed with error:" + err);
        });
    }
}